package threads;

import execution.Manager;
import gui.WindowMain;
import gui.WindowMineResults;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.Set;

import recordsDatabase.Person;
import resultsDatabase.Field;
import resultsDatabase.ListOfResults;
import resultsDatabase.Result;

public class SetGeneratorAndMiner extends Thread {
	private int start;
	private int end;
	private int elements;
	private ArrayList<Field> selectedFields;
	private WindowMain window;
	private WindowMineResults windowResults;
	private boolean go = true;
	private boolean pause = false;
	private Manager manager;

	public SetGeneratorAndMiner(int s, int e, int el, ArrayList<Field> sFields,
			WindowMain w, WindowMineResults wr,Manager m) {
		start = s;
		end = e;
		elements = el;
		selectedFields = sFields;
		window = w;
		windowResults = wr;
		manager=m;
	}

	public void run() {
		
		//run a binary counter for the number of power elements
		while((start<end)&go) {
			while (pause){
				try {
					sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			// run a binary counter for the number of power elements
			window.updateStatus();
			manager.updateSetsMined();
			// convert the binary number to a string containing n digits
			String binary = intToBinary(start, elements);
			// create a new set
			Set<Field> set = new LinkedHashSet<Field>();
			// convert each digit in the current binary number to the
			// corresponding element
			// in the given set
			for (int j = 0; j < binary.length(); j++) {
				if (binary.charAt(j) == '1')
					set.add(selectedFields.get(j));
			}

			// mine the set and destroy it!
			ArrayList<Person> personsFound = Match(set);
			if (personsFound.size() > 0) {
				Result r = new Result(set, personsFound,this.getName());
				ListOfResults.getInstance().addResult(r);
				windowResults.addToLists(r);
			}
			start++;
		}

	}


	private static String intToBinary(int binary, int digits) {

		String temp = Integer.toBinaryString(binary);
		int foundDigits = temp.length();
		String returner = temp;
		for (int i = foundDigits; i < digits; i++) {
			returner = "0" + returner;
		}

		return returner;
	}

	private ArrayList<Person> Match(Set<Field> set) {
		ArrayList<Person> finalPersonsList = new ArrayList<Person>();
		ArrayList<ArrayList<Person>> personLists = new ArrayList<ArrayList<Person>>();

		// step 1 - copy each set's persons list in the personsList
		for (Field f : set) {
			personLists.add(f.getPersonsList());
		}

		// step 2 - compare the lists and find common elements
		if (personLists.size()>1){
			ArrayList<Person> tempList = new ArrayList<Person>();
			tempList=intersectionJoin(personLists.get(0),personLists.get(1));
			if (personLists.size()>2){
				for(int i=2;i<personLists.size();i++){
					tempList=intersectionJoin(tempList,personLists.get(i));
				}
			}
			finalPersonsList=tempList;
		} else if (personLists.size()>=1) finalPersonsList = personLists.get(0);


		return finalPersonsList;
	}

	public ArrayList<Person> intersectionJoin(ArrayList<Person> pList1,ArrayList<Person> pList2){
		ArrayList<Person> mergedList = new ArrayList<Person>();
		//iterate through the first list, since persons must be in both lists
		//we do not need to check both lists
		for (Person p:pList1){
			if (pList2.contains(p)&!mergedList.contains(p)){
					mergedList.add(p);
			}
		}
		mergedList.trimToSize();
		return mergedList;
	}


	public void noGo() {
		pause=false;
		go = false;
	}

	public void pauseToggle(){
		if (pause) pause=false;
		else if (!pause) pause=true;
	}
}
